package com.gopay.bis.icbc.bcdl.operation;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.gopay.common.cipher.utils.LoggerMaskUtils;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpStatus;

import com.gopay.common.constants.bank.IcbcConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.exception.GopayException;

public class HttpTransport {
	/** Logger for logging information. */
	protected Log log = LogFactory.getLog(this.getClass());
	/** Request host. */
	private String url = null;
	/** Connect timeout. */
	private int timeout = 10000;
	/** Default retry connect times. */
	private int retryConnTimes = 1;
	/** 发送编码 */
	private String sendEncoding = "GBK";

	/**
	 * Default constructor.
	 */
	public HttpTransport() {
	}

	/**
	 * 发送报文.
	 * 
	 * @param obj
	 *            报文.
	 * @return 返回报文体.
	 * @throws GopayException
	 */
	public Object submit(Object obj) throws GopayException {
		HttpClient client = new HttpClient();
		PostMethod method = null;
		byte[] responseBody = null;
		int statusCode = 0;
		try {
			String userID = "";// 证书ID,拼接到URL地址后面作为参数
			String SendTime = "";// 包序列ID,拼接到URL地址后面作为参数
			String packageID = "";// 请求时间,拼接到URL地址后面作为参数
			// 为这三个参数赋值
			if (obj instanceof Map) {
				Map paraMap = (Map) obj;
				for (Iterator iter = paraMap.keySet().iterator(); iter
						.hasNext();) {
					String key = (String) iter.next();
					if (key.equals(IcbcConstants.USER_ID)) {
						userID = (String) paraMap.get(key);
					}
					if (key.equals(IcbcConstants.PACKAGE_ID)) {
						packageID = (String) paraMap.get(key);
					}
					if (key.equals(IcbcConstants.SEND_TIME)) {
						SendTime = (String) paraMap.get(key);
					}
				}
			}
			
			// 拼接前面的三个参数
			method = new PostMethod(this.url + "?userID=" + userID
					+ "&PackageID=" + packageID + "&SendTime=" + SendTime);
			method.getParams().setParameter(
					HttpMethodParams.RETRY_HANDLER,
					new DefaultHttpMethodRetryHandler(this.retryConnTimes,
							false));
			method.getParams().setSoTimeout(30000);
			client.getParams().setSoTimeout(20000);
			client.getHttpConnectionManager().getParams()
					.setSoTimeout(this.timeout);

			if (StringUtils.isNotEmpty(sendEncoding)) {
				method.getParams().setParameter(
						HttpMethodParams.HTTP_CONTENT_CHARSET, sendEncoding);
			}
			method.setRequestHeader("User-Agent", "Rich Powered/1.0");
			if (obj instanceof Map) {
				Map paraMap = (Map) obj;
				if (paraMap != null) {
					method.addParameter(IcbcConstants.VERSION,
							(String) paraMap.get(IcbcConstants.VERSION));
					method.addParameter(IcbcConstants.TRANS_CODE,
							(String) paraMap.get(IcbcConstants.TRANS_CODE));
					method.addParameter(IcbcConstants.BANK_CODE,
							(String) paraMap.get(IcbcConstants.BANK_CODE));

					method.addParameter(IcbcConstants.GROUP_CIS,
							(String) paraMap.get(IcbcConstants.GROUP_CIS));

					method.addParameter(IcbcConstants.ID,
							(String) paraMap.get(IcbcConstants.ID));

					method.addParameter(IcbcConstants.PACKAGE_ID,
							(String) paraMap.get(IcbcConstants.PACKAGE_ID));

					method.addParameter(IcbcConstants.CERT,
							(String) paraMap.get(IcbcConstants.CERT));

					method.addParameter(IcbcConstants.REQ_DATA,
							(String) paraMap.get(IcbcConstants.REQ_DATA));
				}
				Map logMap = new HashMap();
				logMap.putAll(paraMap);
				String reqData = (String)logMap.get(IcbcConstants.REQ_DATA);
				logMap.put(IcbcConstants.REQ_DATA, LoggerMaskUtils.maskString(reqData));
				log.info("Sent Data: \n" + logMap);
			} else if (obj instanceof byte[]) {
				method.setRequestEntity(new ByteArrayRequestEntity((byte[]) obj));
				log.info("Sent Data: \n" + new String((byte[]) obj));
			} else {
				log.info("submit(Object obj): obj should be Map or byte[]");
				throw new GopayException(ProcCodeConstants.PROC_CODE_100E6047);
			}

			
			
			log.info(url+"HttpTransport向前置软件448发送交易报文,timeout=" + timeout);
			statusCode = client.executeMethod(method);
			responseBody = method.getResponseBody();
			log.info("HttpTransport从前置软件448接收到银行交易返回信息，返回处理: \n"
					+ new String((byte[]) responseBody));
		} catch (HttpException e) {
			log.fatal("Fatal protocol error while try connect to [" + url + "]");
			log.fatal("Trace: " + e.getMessage());
			log.info("严重***HttpTransport未从前置软件448接收到银行交易返回信息");
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6047);
		} catch (IOException e) {
			log.fatal("Fatal transport error while try connect to [" + url
					+ "]");
			log.fatal("Cause: " + e.getMessage());
			log.info("严重***HttpTransport未从前置软件448接收到银行交易返回信息");
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6047);
		} catch (Exception e) {
            log.fatal("Fatal transport error while try connect to [" + url
                    + "]");
            log.error("Cause: ", e);
            log.info("严重***HttpTransport未从前置软件448接收到银行交易返回信息");
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6047);
        } finally {
			method.releaseConnection();
			client.getHttpConnectionManager().closeIdleConnections(0);
		}
		if (statusCode != HttpStatus.SC_OK) {
			if (null != responseBody) {
				log.error("Answer from [" + url + "] status code: [" + statusCode
						+ "] response contents: [" + new String(responseBody)
						+ "]");
			} else {
				log.error("Answer from [" + url + "] status code: [" + statusCode
						+ "] response contents: [null]");
			}
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6047);
		}
		return responseBody;
	}

	/**
	 * Set timeout.
	 * 
	 * @param timeout
	 *            the timeout to set.
	 */
	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	/**
	 * Set url.
	 * 
	 * @param url
	 *            the url to set.
	 */
	public void setUrl(String url) {
		this.url = url;
	}

	/**
	 * Set retry connect times.
	 * 
	 * @param retryConnTimes
	 *            the retryConnTimes to set.
	 */
	public void setRetryConnTimes(int retryConnTimes) {
		this.retryConnTimes = retryConnTimes;
	}

	public void setSendEncoding(String sendEncoding) {
		this.sendEncoding = sendEncoding;
	}
	
	

}
